#include "stdint.h"
#include "stdio.h"
// 根据平台选择包含的头文件
#include "stm32f1xx.h"

//#include "stm32f0xx.h"
#if (__CORTEX_M == 0x00U)
#define SCB_CFSR        (*(volatile const unsigned *)0xE000ED28) /* Configurable Fault Status Register */
#define SCB_HFSR        (*(volatile const unsigned *)0xE000ED2C) /* HardFault Status Register */
#define SCB_MMAR        (*(volatile const unsigned *)0xE000ED34) /* MemManage Fault Address register */
#define SCB_BFAR        (*(volatile const unsigned *)0xE000ED38) /* Bus Fault Address Register */
#define SCB_AIRCR       (*(volatile unsigned long *)0xE000ED0C)  /* Reset control Address Register */
#define SCB_RESET_VALUE 0x05FA0004                               /* Reset value, write to SCB_AIRCR can reset cpu */

#define SCB_CFSR_MFSR   (*(volatile const unsigned char*)0xE000ED28)  /* Memory-management Fault Status Register */
#define SCB_CFSR_BFSR   (*(volatile const unsigned char*)0xE000ED29)  /* Bus Fault Status Register */
#define SCB_CFSR_UFSR   (*(volatile const unsigned short*)0xE000ED2A) /* Usage Fault Status Register */

#define SCB_HFSR_VECTTBL_Pos                1U                                            /*!< SCB HFSR: VECTTBL Position */
#define SCB_HFSR_VECTTBL_Msk               (1UL << SCB_HFSR_VECTTBL_Pos)                  /*!< SCB HFSR: VECTTBL Mask */
#endif

//#include "pt-thread.h"
//修改为平台相应的log输出功能

#define hf_printf(message)												\
do                                                                            \
{                                                                             \
	/*printf message; */                                                    \
}                                                                             \
while (0)

/* Compiler Related Definitions */
#ifdef __CC_ARM                         /* ARM Compiler */
    #define HF_WEAK                     __weak
#elif defined (__GNUC__)                /* GNU GCC Compiler */
    #define HF_WEAK                     __attribute__((weak))
#else
    #error not supported tool chain
#endif

/**
 * @brief Contents of the stack.
 *
 * This structure is used to re-create the stack layout after a HardFault exception was raised.
 */
typedef struct HardFault_stack
{
    uint32_t r0;  ///< R0 register.
    uint32_t r1;  ///< R1 register.
    uint32_t r2;  ///< R2 register.
    uint32_t r3;  ///< R3 register.
    uint32_t r12; ///< R12 register.
    uint32_t lr;  ///< Link register.
    uint32_t pc;  ///< Program counter.
    uint32_t psr; ///< Program status register.
} HardFault_stack_t;


HF_WEAK void before_c_handler(uint32_t * p_stack_address)
{

}


HF_WEAK void HardFault_process(HardFault_stack_t * p_stack)
{
	// 根据需要处理

    // Restart the system by default
//    NVIC_SystemReset();
}

static void HardFault_c_handler(uint32_t * p_stack_address);
void easy_hardfault_parse(uint32_t fault_handler_lr, uint32_t fault_handler_sp)
{
	(void)fault_handler_lr;
	(void)fault_handler_sp;
	
	before_c_handler((uint32_t *)fault_handler_sp);
	
#ifdef PT_THREAD_H
	struct pt *cur_thread = get_cur_thread();
	hf_printf( ( "latest thread addr: 0x%08X\n", cur_thread ) );
	hf_printf( ("latest thread id: 0x%X\n", cur_thread->thread_id) );	// 打印出最近运行的线程ID
	hf_printf( ("latest thread entry line: %d\n", cur_thread->lc) );	// 打印出该线程运行到的最近行号
#endif
	HardFault_c_handler( (uint32_t *)fault_handler_sp );
	while(1);
}


static void HardFault_c_handler(uint32_t * p_stack_address)
{

#if (__CORTEX_M == 0x03U || __CORTEX_M == 0x04U)
	uint32_t cfsr = SCB->CFSR;
	uint32_t hfsr = SCB->HFSR;
#elif (__CORTEX_M == 0x00U)
	uint32_t cfsr = SCB_CFSR;
	uint32_t hfsr = SCB_HFSR;
#endif
	
#ifndef CFSR_MMARVALID
  #define CFSR_MMARVALID (1 << (0 + 7))
#endif

#ifndef CFSR_BFARVALID
  #define CFSR_BFARVALID (1 << (8 + 7))
#endif

    HardFault_stack_t * p_stack = (HardFault_stack_t *)p_stack_address;
    static const char *cfsr_msgs[] = {
        [0]  = "The processor has attempted to execute an undefined instruction",
        [1]  = "The processor attempted a load or store at a location that does not permit the operation",
        [2]  = NULL,
        [3]  = "Unstack for an exception return has caused one or more access violations",
        [4]  = "Stacking for an exception entry has caused one or more access violations",
        [5]  = "A MemManage fault occurred during floating-point lazy state preservation",
        [6]  = NULL,
        [7]  = NULL,
        [8]  = "Instruction bus error",
        [9]  = "Data bus error (PC value stacked for the exception return points to the instruction that caused the fault)",
        [10] = "Data bus error (return address in the stack frame is not related to the instruction that caused the error)",
        [11] = "Unstack for an exception return has caused one or more BusFaults",
        [12] = "Stacking for an exception entry has caused one or more BusFaults",
        [13] = "A bus fault occurred during floating-point lazy state preservation",
        [14] = NULL,
        [15] = NULL,
        [16] = "The processor has attempted to execute an undefined instruction",
        [17] = "The processor has attempted to execute an instruction that makes illegal use of the EPSR",
        [18] = "The processor has attempted an illegal load of EXC_RETURN to the PC, as a result of an invalid context, or an invalid EXC_RETURN value",
        [19] = "The processor has attempted to access a coprocessor",
        [20] = NULL,
        [21] = NULL,
        [22] = NULL,
        [23] = NULL,
        [24] = "The processor has made an unaligned memory access",
        [25] = "The processor has executed an SDIV or UDIV instruction with a divisor of 0",
    };

    if (p_stack != NULL)
    {
        // Print information about error.
        hf_printf( ("HARD FAULT at 0x%08X", p_stack->pc) );
        hf_printf(("  R0:  0x%08X  R1:  0x%08X  R2:  0x%08X  R3:  0x%08X",
                             p_stack->r0, p_stack->r1, p_stack->r2, p_stack->r3));
        hf_printf(("  R12: 0x%08X  LR:  0x%08X  PSR: 0x%08X",
                             p_stack->r12, p_stack->lr, p_stack->psr));
		
#ifdef __CC_ARM
		hf_printf(("run: addr2line -e **.axf -f 0x%08X\n", p_stack->pc));	// 运行addr2line找出具体源代码行号
#elif defined __GNUC__
		hf_printf(("run: addr2line -e **.elf -f 0x%08X\n", p_stack->pc));	// 运行addr2line找出具体源代码行号
#endif
    }
    else
    {
        hf_printf(("Stack violation: stack pointer outside stack area."));
    }

    if (hfsr & SCB_HFSR_VECTTBL_Msk)
    {
        hf_printf(("Cause: BusFault on a vector table read during exception processing."));
    }

    for (uint32_t i = 0; i < sizeof(cfsr_msgs) / sizeof(cfsr_msgs[0]); i++)
    {
        if (((cfsr & (1 << i)) != 0) && (cfsr_msgs[i] != NULL))
        {
            hf_printf(("Cause: %s.", (uint32_t)cfsr_msgs[i]));
        }
    }

    if (cfsr & CFSR_MMARVALID)
    {
        hf_printf(("MemManage Fault Address: 0x%08X", SCB->MMFAR));
    }

    if (cfsr & CFSR_BFARVALID)
    {
        hf_printf(("Bus Fault Address: 0x%08X", SCB->BFAR));
    }
	
	
	#define DEBUGEVT 	((uint32_t)1 << 31)
	#define FORCED 		(1 << 30)
	#define VECTBL 		(1 << 1)
    if (hfsr & DEBUGEVT)
    {
        hf_printf( ( "DEBUGEVT\n" ) );
    }	
    if (hfsr & FORCED)
    {
        hf_printf( ( "FORCED\n" ) );
    }
    if (hfsr & VECTBL)
    {
        hf_printf( ( "VECTBL\n" ) );
    }	
	


    HardFault_process((HardFault_stack_t *)p_stack_address);

}
